function maxSubarraySumCircular(nums: number[]): number {
    let n = nums.length;
    const leftMax = new Array(n).fill(0);
    // 对坐标为 0 处的元素单独处理，避免考虑子数组为空的情况
    leftMax[0] = nums[0];
    let leftSum = nums[0];
    let pre = nums[0];
    let res = nums[0];
    for (let i = 1; i < n; i++) {
        // 正常的状态转移方程
        pre = Math.max(pre + nums[i], nums[i]);
        //? 记录答案，可能存在不需要从尾到头的情况
        res = Math.max(res, pre);
        leftSum += nums[i];
        //? 延续状态 或者加上当前值
        leftMax[i] = Math.max(leftMax[i - 1], leftSum);
    }

    // 从右到左枚举后缀，固定后缀，选择最大前缀
    // nums[0:i]为数组的某一前缀，nums[j:n] 为数组的某一后缀。求解时，我们可以枚举 jjj，固定 sum(nums[j:n])的值，然后找到右端点坐标范围在 [0,j−1] 的最大前缀和，将它们相加更新答案。
    let rightSum = 0;
    for (let i = n - 1; i > 0; i--) {
        rightSum += nums[i];
        res = Math.max(res, rightSum + leftMax[i - 1]);
    }
    return res;
};
